#include <cstdint>
#include <functional>
#include <iostream>
#include <memory>
#include <unistd.h>
#include <unordered_map>
#include <vector>

using TaskFunc = std::function<void()>; // 析构时调用执行任务
using ReleaseFunc =
    std::function<void()>; // 析构时调用删除时间轮中的任务表中记录

class TimerTask {
private:
  uint32_t _timeout;    // 超时时间,也就是多久后销毁
  uint64_t _id;         // 任务id，唯一标识任务
  TaskFunc _task;       // 定时任务
  ReleaseFunc _release; // 清除任务表中记录
  bool _cancle;         // 任务是否被取消
public:
  TimerTask(uint64_t id, uint32_t timeout, TaskFunc task)
      : _timeout(timeout), _id(id), _task(task), _cancle(false) {}
  ~TimerTask() {
    if (!_cancle) {
      _task();
    }
    if (_release) {
      _release();
    }
  }
  uint32_t timeout() { return _timeout; }
  void setRelease(ReleaseFunc release) { _release = release; }
  void cancle() { _cancle = true; }
};

class TimerWheel {
private:
  using TaskPtr = std::shared_ptr<TimerTask>;
  using TaskWeak = std::weak_ptr<TimerTask>;
  uint32_t _tick;                           // 时间轮跳动的指针
  uint32_t _capacity;                       // 时间轮大小
  std::vector<std::vector<TaskPtr>> _wheel; // 时间轮，用来放置任务
  std::unordered_map<uint64_t, TaskWeak>
      _taskTabel; // 任务表，用来记录有哪些任务存在
private:
  void removeTaskInfo(uint64_t id) // 删除任务表中记录的信息
  {
    auto it = _taskTabel.find(id);
    if (it != _taskTabel.end()) {
      _taskTabel.erase(it);
    }
  }

public:
  TimerWheel() : _tick(0), _capacity(60), _wheel(_capacity) {}
  void addTask(uint64_t id, uint32_t timeout, TaskFunc task) // 添加任务
  {
    TaskPtr ptr(new TimerTask(id, timeout, task));
    int pos = (_tick + timeout) % _capacity;
    _wheel[pos].push_back(ptr); // 将任务放入时间轮
    _taskTabel[id] = ptr;       // 记录任务信息到任务表
    ptr->setRelease(std::bind(&TimerWheel::removeTaskInfo, this,
                              id)); // 移除记录的函数也要设置好
  }
  void timerRefresh(uint64_t id) {
    auto it = _taskTabel.find(id);
    if (it == _taskTabel.end()) {
      std::cout << "不存在这个任务" << std::endl;
      return; // 没有这个任务存在，直接返回
    }
    TaskPtr ptr(it->second.lock());
    int pos = (_tick + ptr->timeout()) % _capacity;
    _wheel[pos].push_back(ptr); // 将任务放入时间轮
  }
  void cancleTask(uint64_t id) {
    auto it = _taskTabel.find(id);
    if (it == _taskTabel.end()) {
      std::cout << "不存在这个任务" << std::endl;
      return; // 没有这个任务存在，直接返回
    }
    TaskPtr ptr(it->second.lock());
    ptr->cancle(); // 取消这个任务
  }
  void runTick() {
    // 移动指针
    _tick += 1;
    _tick %= _capacity;
    _wheel[_tick].clear(); // 执行这个位置的所有任务
  }

  ~TimerWheel() {}
};

// 下面是测试用例

class Test {
public:
  Test() { std::cout << "构造" << std::endl; }
  ~Test() { std::cout << "析构" << std::endl; }
};

void DelTest(Test *t) { delete t; }

int main() {
  TimerWheel tw;

  Test *t = new Test();

  tw.addTask(888, 5, std::bind(DelTest, t));

  for (int i = 0; i < 3; i++) {
    sleep(1);
    tw.timerRefresh(888); // 刷新定时任务
    tw.runTick();         // 向后移动秒针
    std::cout << "刷新了一下定时任务，重新需要3s中后才会销毁\n";
  }
  //tw.cancleTask(888);
  while (1) {
    sleep(1);
    std::cout << "-------------------\n";
    tw.runTick(); // 向后移动秒针
  }
  return 0;
}